package hk.linkcredit.walletservice.wallet.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import hk.linkcredit.walletservice.constant.Status;
import hk.linkcredit.walletservice.constant.WalletConstants;
import hk.linkcredit.walletservice.exception.BizException;
import hk.linkcredit.walletservice.utils.IdUtils;
import hk.linkcredit.walletservice.utils.StringUtils;
import hk.linkcredit.walletservice.wallet.domain.entity.WalletAmount;
import hk.linkcredit.walletservice.wallet.domain.entity.WalletOrder;
import hk.linkcredit.walletservice.wallet.domain.vo.WalletAccountInfo;
import hk.linkcredit.walletservice.wallet.domain.vo.WalletOrderReq;
import hk.linkcredit.walletservice.wallet.domain.vo.WalletRepayReq;
import hk.linkcredit.walletservice.wallet.domain.vo.WalletWithdrawReq;
import hk.linkcredit.walletservice.wallet.mapper.WalletOrderMapper;
import hk.linkcredit.walletservice.wallet.service.WalletAmountService;
import hk.linkcredit.walletservice.wallet.service.WalletFlowService;
import hk.linkcredit.walletservice.wallet.service.WalletOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 钱包订单表 服务实现类
 * </p>
 *
 * @author LinkCredit
 * @since 2022-06-10 15:26:33
 */
@Slf4j
@Service
public class WalletOrderServiceImpl extends ServiceImpl<WalletOrderMapper, WalletOrder> implements WalletOrderService {

    @Autowired
    WalletFlowService walletFlowService;

    @Autowired
    WalletAmountService walletAmountService;

    @Override
    public WalletOrder generateWalletOrder(String orderType, BigDecimal actualAmount, WalletWithdrawReq walletWithdrawReq, WalletAccountInfo walletAccount) {
        log.info("开始创建提现/退款订单 >>> orderType = {}，walletWithdrawReq = {}，walletAccount = {}", orderType, walletWithdrawReq, walletAccount);

        String orderSerialNo = getOrderSerialNo(orderType);
        log.debug("订单流水号：{}", orderSerialNo);

        WalletOrder walletOrder = WalletOrder.builder()
                .walletNo(walletAccount.getWalletNo())
                .custNo(walletAccount.getCustNo())
                .serialNo(orderSerialNo)
                .orderType(orderType)
                .applyAmount(walletWithdrawReq.getApplyAmount())
                .amount(actualAmount)
                .serviceFee(walletWithdrawReq.getApplyAmount().multiply(walletAccount.getServiceRate()))
                .bankCode(walletWithdrawReq.getBankCode())
                .bankAccount(walletWithdrawReq.getBankAccount())
                .fromWhere(walletAccount.getWalletNo())
                .toDest(walletAccount.getCustNo())
                .minWithdrawBalance(walletAccount.getMinWithdrawBalance())
                .minWithdrawBonus(walletAccount.getMinWithdrawBonus())
                .serviceRate(walletAccount.getServiceRate())
                .walletType(walletWithdrawReq.getWalletType())
                .orderStatus(WalletConstants.WALLET_ORDER_STATUS_UNDER_REVIEW)
                .build();

        this.save(walletOrder);

        log.info("创建提现订单结束 >>> ");
        return walletOrder;
    }

    @Override
    public String generateWalletOrder(String orderType, JSONObject repayAmtSplit, WalletRepayReq walletRepayReq, WalletAccountInfo walletAccount) {
        log.info("开始创建还款订单 >>> orderType = {}，repayAmtSplit = {}，walletRepayReq = {}，walletAccount = {}", orderType, repayAmtSplit, walletRepayReq, walletAccount);

        String orderStatus = null;
        if (StringUtils.equals(orderType, WalletConstants.ORDER_TYPE_REPAY)) {
            orderStatus = WalletConstants.WALLET_ORDER_STATUS_REPAY_PENDING;
        } else if (StringUtils.equals(orderType, WalletConstants.ORDER_TYPE_DEFERRED_REPAY)) {
            orderStatus = WalletConstants.WALLET_ORDER_STATUS_DEFERRED_PENDING;
        }

        List<WalletOrder> walletOrderList = new ArrayList<>();

        String orderSerialNo = IdUtils.serialNo();
        BigDecimal balanceAmt = repayAmtSplit.getBigDecimal("balanceAmt");
        if (balanceAmt.compareTo(BigDecimal.ZERO) > 0) {
            WalletOrder walletBalanceOrder = WalletOrder.builder()
                    .walletNo(walletAccount.getWalletNo())
                    .custNo(walletAccount.getCustNo())
                    .serialNo(getOrderSerialNo(orderType))
                    .orderType(orderType)
                    .applyAmount(walletRepayReq.getApplyAmount())
                    .amount(balanceAmt)
                    .fromWhere(walletAccount.getWalletNo())
                    .toDest("LinkCredit")
                    .batchSerialNo(orderSerialNo)
                    .loanSerialNo(walletRepayReq.getLoanSerialNo())
                    .walletType(WalletConstants.WALLET_ORDER_TYPE_BALANCE)
                    .orderStatus(orderStatus)
                    .build();
            walletOrderList.add(walletBalanceOrder);
        }

        BigDecimal bonusAmt = repayAmtSplit.getBigDecimal("bonusAmt");
        if (bonusAmt.compareTo(BigDecimal.ZERO) > 0) {
            WalletOrder walletBonusOrder = WalletOrder.builder()
                    .walletNo(walletAccount.getWalletNo())
                    .custNo(walletAccount.getCustNo())
                    .serialNo(getOrderSerialNo(orderType))
                    .orderType(orderType)
                    .applyAmount(walletRepayReq.getApplyAmount())
                    .amount(bonusAmt)
                    .fromWhere(walletAccount.getWalletNo())
                    .toDest("LinkCredit")
                    .batchSerialNo(orderSerialNo)
                    .loanSerialNo(walletRepayReq.getLoanSerialNo())
                    .walletType(WalletConstants.WALLET_ORDER_TYPE_BONUS)
                    .orderStatus(orderStatus)
                    .build();
            walletOrderList.add(walletBonusOrder);
        }

        this.saveBatch(walletOrderList);

        log.info("结束创建还款订单 >>>");
        return orderSerialNo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doWalletOrder(WalletOrderReq walletOrderReq, WalletOrder walletOrder) {
        if (this.checkCustNo(walletOrderReq.getCustNo(), walletOrder.getCustNo())) {
            log.error("订单客户号与传参客户号不一致");
            return;
        }

        String orderStatus = walletOrder.getOrderStatus();
        log.info("当前订单状态：currentStatus = {}，targetStatus = {}", orderStatus, WalletConstants.WALLET_ORDER_STATUS_SUCCESS);
        if (!StringUtils.equalsAny(orderStatus, WalletConstants.WALLET_ORDER_STATUS_APPROVED, WalletConstants.WALLET_ORDER_STATUS_PENDING, WalletConstants.WALLET_ORDER_STATUS_RETRIED, WalletConstants.WALLET_ORDER_STATUS_REPAY_PENDING, WalletConstants.WALLET_ORDER_STATUS_DEFERRED_PENDING)) {
            throw new BizException(Status.WALLET_ORDER_STATUS_EXPIRED);
        }

        this.updateWalletOrder(walletOrder.getId(), WalletConstants.WALLET_ORDER_STATUS_SUCCESS, null);

        deductionWalletAmount(walletOrder);

        walletFlowService.createWalletFlowExpend(walletOrder);
    }

    private void deductionWalletAmount(WalletOrder walletOrder) {
        WalletAmount walletAmount = WalletAmount.builder()
                .frozenAmount(walletOrder.getAmount().add(walletOrder.getServiceFee()))
                .walletType(walletOrder.getWalletType())
                .custNo(walletOrder.getCustNo())
                .build();
        walletAmountService.deductionWalletAmount(walletAmount);
    }

    protected void updateWalletOrder(Long orderId, String orderStatus, String message) {
        UpdateWrapper<WalletOrder> wrapper = Wrappers.update();
        wrapper.set("order_status", orderStatus)
                .set("remark", message)
                .eq("id", orderId);
        this.update(wrapper);
    }

    protected boolean checkCustNo(String desCustNo, String tarCustNo) {
        return StringUtils.isNotBlank(desCustNo) && !StringUtils.equals(desCustNo, tarCustNo);
    }

    private BigDecimal getAmt(BigDecimal amount) {
        return amount.compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO : amount;
    }

    private String getOrderSerialNo(String orderType) {
        String type = null;
        switch (orderType) {
            case WalletConstants.ORDER_TYPE_REFUND:
                type = "refund";
                break;
            case WalletConstants.ORDER_TYPE_WITHDRAW:
                type = "withdraw";
                break;
            case WalletConstants.ORDER_TYPE_REPAY:
                type = "repay";
                break;
            case WalletConstants.ORDER_TYPE_DEFERRED_REPAY:
                type = "deferred";
                break;
            default:
                throw new BizException(Status.WALLE_WITHDRAW_TYPE_CANNOT_SUPPORT);
        }
        log.info("创建的订单类型为：{}", type);
        return IdUtils.serialNo(type);
    }
}
